#ifndef STRINGMANIP_CPP
#define STRINGMANIP_CPP

// Includes
#include <string>
#include <sstream>
#include <iostream>
// heh
#define LOWER( c )		( (c) >= 'A' && (c) <= 'Z' ? (c)+'a'-'A' : (c) )
#define UPPER( c )		( (c) >= 'a' && (c) <= 'z' ? (c)+'A'-'a' : (c) )

//////////////////////////////////
// Conversion for unknown types //
//////////////////////////////////
template <typename T>
inline std::string to_str (T a_T) {
  std::ostringstream buffer;
  buffer << a_T;
  return buffer.str();
}

/////////////////////////
// Insertion operators //
/////////////////////////
inline std::string &operator<< (std::string &dest, const char c) {
  dest += c;
  return dest;
}

inline std::string &operator<< (std::string &dest, const char *src) {
  dest.append(src);
  return dest;
}

inline std::string &operator<< (std::string &dest, const std::string &src) {
  dest.append(src);
  return dest;
}

inline std::string &operator<< (std::string &dest, int insertion) {
  dest.append(to_str(insertion));
  return dest;
}

inline std::string &operator<< (std::string &dest, unsigned int insertion) {
  dest.append(to_str(insertion));
  return dest;
}

////////////////////////////
// Uniform Tab Evaluation //
////////////////////////////
inline std::string string_eval_tabs (const int maxlength, const int length) {
  std::string tabs(1, '\t');
  return tabs;
}

// Case insensitive string comparison
int	strcasecmp	(const char *str1, const char *str2);
int	strncasecmp	(const char *str1, const char *str2, unsigned int len);
 
inline int strcasecmp (const std::string &str1, const std::string &str2) {
    return strcasecmp(str1.c_str(), str2.c_str());
}

inline int strncasecmp (const std::string &str1, const std::string &str2, unsigned int len) {
	return strncasecmp(str1.c_str(), str2.c_str(), len);
}

// Case Insensitive string compares, false on unequal, true on if they equal
// g++ was spitting an error about the first one being a reference, so I just made it a plain std::string instead of a reference; g++ (gcc) 3.3.2 20030812 (Debian prerelease)
bool str_cmp( std::string string1, std::string string2 );
bool str_cmp( std::string &string1, char * string2 );
bool str_cmp( char * string1, std::string &string2 );
bool str_cmp( char * string1, char * string2 );

// case insensitive string prefix compares, true if it's prefixed in there. ;)
bool str_prefix( std::string &string1, std::string &string2 );
bool str_prefix( std::string &string1, char * string2 );
bool str_prefix( char * string1, std::string &string2 );
bool str_prefix( char * string1, char * string2 );

bool str_str( char * string1, char * string2 );
bool str_str( std::string string1, std::string string2 );

// normal string dealing functions
char * str_dup( const char *str );

/////////////////////////
//I NEED TO MAKE SURE THESE WORK ALL CORRECTLY
//MULTI-LENGTHED STRINGS ON ALL OF THEM

char			str_empty	[1];

///////////////////////////////////////
 // String Compare (case insensitive) //
 ///////////////////////////////////////
 int strcasecmp (const char *str1, const char *str2) {
 	for (; ((tolower(*str1) - tolower(*str2)) == 0); ++str1, ++str2) {
		if (*str1 == '\0' || *str2 == '\0')
		return 0;
	}

 	return (tolower(*str1) - tolower(*str2));
 }
 
 int strncasecmp (const char *str1, const char *str2, unsigned int len) {
 	for (; ((tolower(*str1) - tolower(*str2)) == 0); ++str1, ++str2) {
 		if (*str1 == '\0' || *str2 == '\0')
			return 0;
 
 		if (--len == 0) break;
 	}
 
 	return (tolower(*str1) - tolower(*str2));
}

///// These functions handle string comparing. They're all case
///// insensitive. 
///////////////////////////////////////////////////////////////
bool str_cmp( std::string string1, std::string string2 ) {
	std::string::iterator cChar, cChar2;	

    if ( string1.empty() )
	    return false;

    if ( string2.empty() )
		return false;

	for ( cChar = string1.begin(), cChar2 = string2.begin(); cChar != string1.end() || cChar2 != string2.end(); cChar++, cChar2++ ) {
		if ( LOWER( (*cChar) ) != LOWER( (*cChar2) ) )
			return false;
	}

	return true;
}

bool str_cmp( std::string &string1, char * string2 ) {
	std::string::iterator cChar;

	if ( string1.empty() )
		return false;

	if ( string2 == NULL )
		return false;

	for ( cChar = string1.begin(); cChar != string1.end() || *string2; ++cChar, string2++ ) {
		if ( LOWER( (*cChar) ) != LOWER( *string2 ) )
			return false;
	}

	return true;
}

bool str_cmp( char * string1, std::string &string2 ) {
	std::string::iterator cChar;

	if ( string1 == NULL )
		return false;

	if ( string2.empty() )
		return false;

	for ( cChar = string2.begin(); cChar != string2.end() || *string1; ++cChar, string1++ ) {
		if ( LOWER( (*string1) ) != LOWER( *cChar ) )
			return false;
	}

	return true;
}

bool str_cmp( char * string1, char * string2 ) {
	if ( string1 == NULL )
	   return false;

    if ( string2 == NULL )
	   return false;

    for ( ; *string1 || *string2; string1++, string2++ ) {
	   if ( LOWER(*string1) != LOWER(*string2) )
	      return false;
    }

    return true;
}

/// end str_cmp

///// These functions handle comparing the beginning of strings
///// (Prefix Matching) They're all case insensitive. 
///////////////////////////////////////////////////////////////
bool str_prefix( std::string &string1, std::string &string2 ) {
	std::string::iterator cChar, cChar2;

    if ( string1.empty() )
	   return false;

    if ( string2.empty() )
	   return false;

    for ( cChar = string1.begin(), cChar2 = string2.begin(); cChar != string1.end(); cChar++, cChar2++ ) {
		if ( LOWER( (*cChar) ) != LOWER( (*cChar2) ) )
			return false;
	}

    return true;
}

bool str_prefix( std::string &string1, char * string2 ) {
	std::string::iterator cChar;

	if ( string1.empty() )
		return false;

	if ( string2 == NULL )
		return false;

	for ( cChar = string1.begin(); cChar != string1.end(); ++cChar, string2++ ) {
		if ( LOWER( (*cChar) ) != LOWER( *string2 ) )
			return false;
	}

	return true;
}

bool str_prefix( char * string1, std::string &string2 ) {
	std::string::iterator cChar;

	if ( string1 == NULL ) 
		return false;

	if ( string2.empty() ) 
		return false;
	for ( cChar = string2.begin(); *string1; ++cChar, string1++ ) {
		if ( LOWER( (*string1) ) != LOWER( *cChar ) )
			return false;
	}

	return true;
}

bool str_prefix( char * string1, char * string2 ) {
	if ( string1 == NULL )
	   return false;

    if ( string2 == NULL )
	   return false;
 

    for ( ; *string1; string1++, string2++ ) {
	   if ( LOWER(*string1) != LOWER(*string2) )
	      return false;
    }

    return true;
}


//// lowerString :: This is a function to convert a string to lowerCase without altering the original
////////////////////////////////////////////
char * lowerString( const char * string1 ) {
    char * str_new;

	str_new = new char[ strlen( string1 ) + 1];	

	for ( unsigned int i = 0; i < ( strlen( string1 ) + 1 ); i++ ) {
	   str_new[i] = LOWER( string1[i] );
    } 
	
	return str_new;
}

//// upperString :: This is a function to convert a string to upperCase without altering the original
////////////////////////////////////////////
char * upperString( const char * string1 ) {
    char * str_new;

	str_new = new char[ strlen( string1 ) + 1];	

	for ( unsigned int i = 0; i < ( strlen( string1 ) + 1 ); i++ ) {
	   str_new[i] = UPPER( string1[i] );
    } 
	
	return str_new;
}

///// Similar to strstr, yet is case insensitive 
///////////////////////////////////////////////////////////////
bool str_str( char * string1, char * string2 ) {
    if ( string1 == NULL ) 
	   return false;

    if ( string2 == NULL )
	   return false;


    if ( strstr( lowerString( string1 ), lowerString( string2 ) ) == NULL )
		return false;
   

    return true;
}

bool str_str( std::string string1, std::string string2 ) {
    if ( string1.empty() ) 
	   return false;

    if ( string2.empty() )
	   return false;


    if ( strstr( lowerString( string1.c_str() ), lowerString( string2.c_str() ) ) == NULL )
		return false;
   

    return true;
}



//// str_dup :: Allocates memory for a pointer and puts a string in it
////////////////////////////////////////////
char * str_dup( const char *str ) {
    char * str_new;

    if ( str[0] == '\0' )
	return &str_empty[0];

    str_new = new char[ strlen(str) + 1 ];
    strcpy( str_new, str );
    return str_new;
}

//// free_string :: Frees the memory in a pointer. ( usually goes along with str_dup )
////////////////////////////////////////////
void free_string( char *pstring ) {
    if ( pstring == NULL || pstring == &str_empty[0] )
	return;

    delete pstring;
    return;
}

#define BUFFER 4096
#define MAX_ARGS 8
#define MAX_ARG_BUFFER 256
#define MAX_INPUT_BUFFER (MAX_ARGS * MAX_ARG_BUFFER)

char input[MAX_INPUT_BUFFER];
char arg[MAX_ARGS][MAX_ARG_BUFFER];
std::string inputs;
std::string args[MAX_ARGS];
char safe_str[BUFFER];

void refresh();
void init( char* );
void parse( std::string& );
void parse( char* );
void parse( const char* );
bool same( std::string&, std::string& );
bool same( char*, char* );
void str_replace( char*, char*, char* );
char* get_ext( char* );
char* split( char* );
void ltrim( char* );
void rtrim( char* );

#define DEBUG
#include "debug.cpp"

void refresh()
{ // Flushes all buffers defined in "stringmanip.h"
	for ( int x=0; x < MAX_ARGS; x++ )
		for ( int y=0; y < MAX_ARG_BUFFER; y++ )
			arg[x][y] = '\0';
	for ( int x=0; x < MAX_INPUT_BUFFER; x++ )
		input[x] = '\0';

	inputs = input;

	for ( int x=0; x < MAX_ARGS; x++ )
		args[x] = arg[x];

	return;
}

void init( char* it )
{
	for ( int x=0; x < (int)strlen(it); x++ )
		it[x] = '\0';
	return;
}

void parse( std::string& stuff )
{
	unsigned int stuff_offset = 0;
	int arg_num = 0;
	int arg_offset = 0;

	for ( stuff_offset=0; stuff_offset < stuff.length(); stuff_offset++ )
	{
		while ( stuff[stuff_offset] != ' ' && stuff[stuff_offset] != '\0' && stuff[stuff_offset] != '\n' )
		{
			args[arg_num][arg_offset] = stuff[stuff_offset];
			arg_offset++;
			stuff_offset++;
		}
			arg_num++;
			arg_offset = 0;
	}

	inputs = stuff;

	for ( unsigned x=0; x < MAX_INPUT_BUFFER; x++ )
		if ( x < inputs.length() )
			input[x] = inputs[x];

	for ( int x=0; x < MAX_ARGS; x++ )
		for ( int y=0; y < MAX_ARG_BUFFER; y++ )
			arg[x][y] = args[x][y];

	return;
}

void parse( char* stuff )
{
	for ( int x=0; x < (int)strlen(stuff) && x < MAX_INPUT_BUFFER; x++ )
		input[x] = stuff[x];

	char* A = &stuff[0];
	int i=0;

	for (int x=0; x < MAX_ARGS; x++)
	{
		while ( *A != ' ' && *A != '\0' && *A != '\n' )
		{
			arg[x][i] = (char)*A;
			A++;
			i++;
		}
		if ( *A == '\0' )
			break;
		A++;
		i=0;
	}

	inputs = input;
	for ( int x=0; x < MAX_ARGS; x++ )
		args[x] = arg[x];

	return;
}

void parse( const char* stuff )
{
	for ( int x=0; x < (int)strlen(stuff) && x < MAX_INPUT_BUFFER; x++ )
		input[x] = stuff[x];

	char* it = new char[(int)strlen(stuff)];
	strcpy( it, stuff );
	char* A = &it[0];
	int i=0;

	for (int x=0; x < MAX_ARGS; x++)
	{
		while ( *A != ' ' && *A != '\0' && *A != '\n' )
		{
			arg[x][i] = (char)*A;
			A++;
			i++;
		}
		if ( *A == '\0' )
			break;
		A++;
		i=0;
	}

	inputs = input;
	for ( int x=0; x < MAX_ARGS; x++ )
		args[x] = arg[x];

	return;
}

bool same( std::string& one, std::string& two )
{
	if ( one == two )
		return true;
	else
		return false;
}

bool same( char* one, char* two )
{
	if ( strcmp( one, two ) == 0 )
		return true;
	else
		return false;
}

void str_replace( char* one, char* two, char* target ) { 
	// Searches through "target" and replaces every instance of "one" with "two".

	int t = (int)strlen(target);
	int o = (int)strlen(one);
	int q = (int)strlen(two);
	int n = t + ( q - o );
	char* temp = new char[n];
	bool good = true;

	if ( t < o )
		return;

	for ( int x=0; x < t-o+1; x++ ) {
		for ( int y=x; y-x < o; y++ ) {
			if ( target[y] != one[y-x] )
				good = false;
		}
		if ( good ) {
			int pos = x, i = x;
			delete [] temp;
			n += q - o;
			temp = new char[n]; // holds final string

			strcpy( temp, target );

			// The substring to be replaced
			for ( int y=0; y < q; i++, y++ )
				temp[i] = two[y];

			// After the substring that was replaced
			for ( int z=pos+o; z < t+1; i++, z++ )
				temp[i] = target[z];

			strcpy( target, temp );
		}
		good = true;
	}

	delete [] temp;

	return;
}

char* get_ext( char* str ) {

	int l = (int)strlen( str );
	int pos = 0;
	bool has_ext = false;
	init( safe_str );
	char* temp = new char[500];
	init( temp );

	for ( int x=0; x < l; x++ ) {
	// Records the last instance of a period in str.
		if ( str[x] == '.' ) {
			pos = x;
			has_ext = true;
		}
	}

	if ( ! has_ext ) {
		strcpy( safe_str, "none" );
		return safe_str;
	} else {
		for ( int x=pos+1, y=0; x < l; x++, y++ )
			safe_str[y] = str[x];
		safe_str[y] = '\0';
		return safe_str;
	}
}

char* split( char* str ) {
	// Returns value of str minus the first argument
	parse( str );

	int start = (int)strlen( arg[0] ) + 1;

	for ( int x=start, y=0; x < (int)strlen( input ); x++, y++ )
		input[y] = input[x];
	input[y] = '\0';

	return input;
}

void rtrim( char* str ) {
	int end = (int)strlen(str)-1;

	while( str[end] == ' ' || str[end] == '\n' || str[end] == '\r' || str[end] == '\t' ) {
		str[end] = '\0';
		end--;
	}

	return;
}

void ltrim( char* str ) {
	if ( str[0] == ' ' || str[0] == '\n' || str[0] == '\r' || str[0] == '\t' ) {
		char* it = new char[(int)strlen(str)];
		for ( int x=0, y=1; y < (int)strlen(str); x++, y++ )
			it[x] = str[y];
		it[x] = '\0';
		strcpy( str, it );
		ltrim( str );

		delete [] it;
	}

	return;
}


//int main()
//{
//	return 0;
//}



#endif // #ifndef STRINGMANIP_CPP